package sipphone.example;

import com.voip.Invite.InputStreamDataSource;

import javax.media.*;
import javax.media.control.TrackControl;
import javax.media.format.AudioFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.sdp.SdpConstants;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

/**
 * Created by RXJ on 2018/1/25.
 */
public class RtpTransmitter {
    String host, jmfFormat;

    int port, sdpFormat;

    Processor processor;

    DataSource processorOut;
    DataSink sink;
    Vector listeners;

    public RtpTransmitter(String host, int port, int sdpFormat) {
        this.host = host;
        this.port = port;
        this.sdpFormat = sdpFormat;

        listeners = new Vector();
        processor= null;
        processorOut = null;
        sink = null;

        switch (sdpFormat) {
            case SdpConstants.PCMU:
                jmfFormat = AudioFormat.ULAW_RTP;
                break;
            case SdpConstants.GSM:
                jmfFormat = AudioFormat.GSM_RTP;
                break;
            case SdpConstants.G723:
                jmfFormat = AudioFormat.G723_RTP;
                break;
            case SdpConstants.DVI4_8000:
                jmfFormat = AudioFormat.DVI_RTP;
                break;
            case SdpConstants.DVI4_16000:
                jmfFormat = AudioFormat.DVI_RTP;
                break;
            case SdpConstants.PCMA:
                jmfFormat = AudioFormat.ALAW;
                break;
            case SdpConstants.G728:
                jmfFormat = AudioFormat.G728_RTP;
                break;
            case SdpConstants.G729:
                jmfFormat = AudioFormat.G729_RTP;
                break;
            default:
                jmfFormat = null;
        }
    }

    public void playFromInputStream (InputStream in, String contentType) {

        DataSource inDataSource = new InputStreamDataSource(in, contentType);
        playSound (inDataSource);

    }

    public void playSound(String soundFile) {
        try {
            MediaLocator fileLocator = new MediaLocator(soundFile);
            DataSource fileDS = Manager.createDataSource(fileLocator);
            playSound (fileDS);
        } catch (NoDataSourceException e) {
            System.out.println(e);
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    public void playSound(DataSource inDataSource) {
        try {
            MediaLocator rtpLocator = new MediaLocator("rtp://" + host + ":"
                    + port + "/audio/" + sdpFormat);
            DataSource rtpDataSource = Manager.createDataSource(rtpLocator);
            processor = Manager.createProcessor(inDataSource);
            for (int i = 0; i < listeners.size(); i++){
                processor.addControllerListener((ControllerListener)listeners.elementAt(i));
            }

            processor.configure();
            int count = 0;
            while ((processor.getState() != Processor.Configured) && (count < 6000)){

                Thread.sleep(100);
                count++;
            }

            // Get the tracks from the processor
            TrackControl[] tracks = processor.getTrackControls();

            // Do we have atleast one track?
            if (tracks == null || tracks.length < 1)
                System.out.println("Couldn't find tracks in processor");

            boolean programmed = false;
            AudioFormat afmt;

            // Search through the tracks for a Audio track
            for (int i = 0; i < tracks.length; i++) {
                Format format = tracks[i].getFormat();
                if (tracks[i].isEnabled() && format instanceof AudioFormat
                        && !programmed) {
                    afmt = (AudioFormat) tracks[i].getFormat();
                    tracks[i]
                            .setFormat(new AudioFormat(jmfFormat, 8000.0, 8, 1));
                    System.err.println("Audio transmitted as:");
                    System.err.println("  " + jmfFormat);
                    // Assume succesful
                    programmed = true;
                } else
                    tracks[i].setEnabled(false);
            }

            // Set the output content descriptor to RAW_RTP
            ContentDescriptor cd = new ContentDescriptor(
                    ContentDescriptor.RAW_RTP);
            processor.setContentDescriptor(cd);
            processor.realize();
            while (processor.getState() != Processor.Realized) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(e);
                }
            }
            processor.prefetch();

            processorOut = processor.getDataOutput();

            sink = Manager.createDataSink(processorOut, rtpLocator);
            sink.open();
            processorOut.start();
            processor.start();
            sink.start();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void addControllerListener (ControllerListener listener) {
        listeners.addElement(listener);
    }

    public void waitUntilDone() throws InterruptedException{
        while (processor.getState() != Processor.Prefetched) {
            Thread.sleep(100);
        }
    }

    public void stop() {
        try {
            if (processorOut != null) {
                processorOut.stop();
                processorOut.disconnect();
            }

            if (sink != null){
                sink.close();
            }

            if (processor != null) {
                processor.stop();
                processor.deallocate();
                processor.close();
            }
        } catch (IOException e) {

        }

    }

}